package com.fastwire.carriere.hibernate.daoimpl;

import java.util.Date;
import java.util.List;

import org.hibernate.SQLQuery;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import com.fastwire.carriere.common.constant.AppConstants;
import com.fastwire.carriere.common.util.CommonLogger;
import com.fastwire.carriere.common.util.DateUtil;
import com.fastwire.carriere.dao.DAOException;
import com.fastwire.carriere.dao.DAOFactory;
import com.fastwire.carriere.inventory.entity.CrossConnect;
import com.fastwire.carriere.inventory.entity.FDFr;
import com.fastwire.carriere.inventory.entity.NetworkElement;
import com.fastwire.carriere.inventory.entity.NetworkEntity;
import com.fastwire.carriere.inventory.entity.ProtectionGroup;

// TODO: Auto-generated Javadoc
/**
 * The Class AbstractDAOImpl.
 */
public class AbstractDAOImpl {

	/** The hibernate template. */
	private HibernateTemplate hibernateTemplate = new HibernateTemplate();

	/**
	 * Save or update.
	 * 
	 * @param obj
	 *            the obj
	 * @throws DAOException
	 *             the dAO exception
	 */
	public void saveOrUpdate(Object obj) throws DAOException {
		getHibernateTemplate().saveOrUpdate(obj);
	}

	/**
	 * Merge.
	 * 
	 * @param obj
	 *            the obj
	 * @throws DAOException
	 *             the dAO exception
	 */
	public void merge(Object obj) throws DAOException {
		Session session = HibernateUtil.openSession();
		try {

			session.beginTransaction();
			session.merge(obj);
			session.getTransaction().commit();
		} catch (Exception ex) {
			if (session.getTransaction().isActive()) {
				session.getTransaction().rollback();
			}
			throw new DAOException(ex);
		} finally {
			HibernateUtil.close(session);

		}
	}

	/**
	 * Save or update all.
	 * 
	 * @param objList
	 *            the obj list
	 * @throws DAOException
	 *             the dAO exception
	 */
	//This method is not used directly, it is called from doFullConcurrentDiscovery
	public void saveOrUpdateAll(List objList) throws DAOException {
		Session session = HibernateUtil.openSession();
		try {
			int count = 0;
			session.beginTransaction();
            //invalidateAll(session, NetworkEntity.class.getSimpleName());  // modified on 20120412
			invalidateAll(session); // modified on 20120418
			
			for (Object obj : objList) {

				//session.saveOrUpdate(obj);
				session.persist(obj);
				if (++count % 50 == 0) {
					session.flush();
					session.clear();

				}
				CommonLogger.info(this, "Inserting to DB: " + obj.getClass().getCanonicalName() + " , total entities in session" + 
						+ session.getStatistics().getEntityCount());

			}

			session.getTransaction().commit();

		} catch (Exception ex) {
			if (session.getTransaction().isActive()) {
				session.getTransaction().rollback();
			}
			throw new DAOException(ex);
		} finally {
			HibernateUtil.close(session);
		}
	}

	//--------------------------------------------------------------------;
	// modified on 20120413
	// for adhoc
	public void saveOrUpdateAdhoc(List objList) throws DAOException {
		
		if(null==objList || objList.size()<=0) {
			return;
		}
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		
		try {
			int count = 0;
			for (Object obj : objList) {

				//session.saveOrUpdate(obj);
				session.save(obj);
				if (++count % 50 == 0) {
					session.flush();
					session.clear();
				}
				CommonLogger.info(this, "total entities in session"
						+ session.getStatistics().getEntityCount());
			}
			
			tx.commit();
		} catch (Exception ex) {
			if(tx.isActive()) {
				tx.rollback();
			}
			throw new DAOException(ex);
		} finally {
			HibernateUtil.close(session);
		}
	}

	//Invalidates only CrossConnect, FDFr , ProtectionGroup
	public void saveOrUpdateAllService(List objList) throws DAOException {
		Session session = HibernateUtil.openSession();
		try {
			int count = 0;
			session.beginTransaction();
			
			// added on 20120412
			invalidateAll(session, CrossConnect.class);  // modified on 20120412
			invalidateAll(session, FDFr.class);  // modified on 20120412
			invalidateAll(session, ProtectionGroup.class);  // modified on 20120412
			
			for (Object obj : objList) {

				session.saveOrUpdate(obj);
				if (++count % 50 == 0) {
					session.flush();
					session.clear();

				}
				CommonLogger.info(this, "total entities in session"
						+ session.getStatistics().getEntityCount());

			}

			session.getTransaction().commit();

		} catch (Exception ex) {
			if (session.getTransaction().isActive()) {
				session.getTransaction().rollback();
			}
			throw new DAOException(ex);
		} finally {
			HibernateUtil.close(session);

		}
	}

	/**
	 * Merge all.
	 * 
	 * @param objList
	 *            the obj list
	 * @throws DAOException
	 *             the dAO exception
	 */
	public void mergeAll(List objList) throws DAOException {
		Session session = HibernateUtil.openSession();
		try {
			int count = 0;
			int neNo = 0;
			session.beginTransaction();
			for (Object obj : objList) {

				session.merge(obj);
				if (++count % 50 == 0) {
					session.flush();
					session.clear();
				}
				CommonLogger.debug(this, "total entities in session"
						+ session.getStatistics().getEntityCount());

				if (obj instanceof NetworkElement) {
					CommonLogger.info(this, "handle ce_network_element:"
							+ neNo++);

				}
			}

			session.getTransaction().commit();
		} catch (Exception ex) {
			if (session.getTransaction().isActive()) {
				session.getTransaction().rollback();
			}
			throw new DAOException(ex);
		} finally {
			HibernateUtil.close(session);

		}
	}

	/**
	 * Delete.
	 * 
	 * @param obj
	 *            the obj
	 * @throws DAOException
	 *             the dAO exception
	 */
	public void delete(Object obj) throws DAOException {
		Session session = HibernateUtil.openSession();
		try {

			session.beginTransaction();
			session.delete(obj);
			session.getTransaction().commit();
		} catch (Exception ex) {
			if (session.getTransaction().isActive()) {
				session.getTransaction().rollback();
			}
			throw new DAOException(ex);
		} finally {
			HibernateUtil.close(session);

		}
	}

	/**
	 * Delete all.
	 * 
	 * @param objList
	 *            the obj list
	 * @throws DAOException
	 *             the dAO exception
	 */
	public void deleteAll(List objList) throws DAOException {
		Session session = HibernateUtil.openSession();
		try {

			session.beginTransaction();
			for (Object obj : objList)
				session.delete(obj);
			session.getTransaction().commit();
		} catch (Exception ex) {
			if (session.getTransaction().isActive()) {
				session.getTransaction().rollback();
			}
			throw new DAOException(ex);
		} finally {
			HibernateUtil.close(session);

		}
	}

	/**
	 * Find all.
	 * 
	 * @param classObj
	 *            the class obj
	 * @return the list
	 * @throws DAOException
	 *             the dAO exception
	 */
	public List findAll(Class classObj) throws DAOException {
		DetachedCriteria criteria = DetachedCriteria.forClass(classObj);

		return getHibernateTemplate().findObjsByCriteria(criteria, true, false);
	}

	/**
	 * Find objby name.
	 * 
	 * @param name
	 *            the name
	 * @param classObj
	 *            the class obj
	 * @return the object
	 * @throws DAOException
	 *             the dAO exception
	 */
	public Object findObjbyName(String name, Class classObj)
			throws DAOException {

		List objList = findObjListbyName(name, classObj);

		if (objList.size() > 0) {
			return objList.get(0);
		} else {
			return null;
		}

	}

	/**
	 * Find obj listby name.
	 * 
	 * @param name
	 *            the name
	 * @param classObj
	 *            the class obj
	 * @return the list
	 * @throws DAOException
	 *             the dAO exception
	 */
	public List findObjListbyName(String name, Class classObj)
			throws DAOException {

		DetachedCriteria criteria = DetachedCriteria.forClass(classObj);

		Criterion nameCriterion = Restrictions.eq("emsNativeName", name);
		Criterion nativeNameCriterion = Restrictions.like("name", name,
				MatchMode.ANYWHERE);
		criteria.add(Restrictions.or(nameCriterion, nativeNameCriterion));

		criteria = criteria.add(getStatusCriteria());

		return getHibernateTemplate().findObjsByCriteria(criteria, false, true);

	}

	/**
	 * Find distinct all.
	 * 
	 * @param classObj
	 *            the class obj
	 * @param property
	 *            the property
	 * @return the list
	 * @throws DAOException
	 *             the dAO exception
	 */
	public List findDistinctAll(Class classObj, String property)
			throws DAOException {
		DetachedCriteria criteria = DetachedCriteria.forClass(classObj);
		criteria = criteria.add(getStatusCriteria());
		criteria.setProjection(Projections.distinct(Projections
				.property(property)));

		return getHibernateTemplate().findObjsByCriteria(criteria, true, false);

	}

	/**
	 * Gets the eMS namesby criterion.
	 * 
	 * @param emsNativeName
	 *            the ems native name
	 * @param className
	 *            the class name
	 * @return the eMS namesby criterion
	 * @throws DAOException
	 *             the dAO exception
	 */
	public List getEMSNamesbyCriterion(String emsNativeName, Class className)
			throws DAOException {

		MatchMode searchMode = MatchMode.ANYWHERE;
		if (emsNativeName.startsWith("?") && !emsNativeName.endsWith("*")) {
			searchMode = MatchMode.END;
		} else if (!emsNativeName.startsWith("?")
				&& emsNativeName.endsWith("*")) {
			searchMode = MatchMode.START;
		} else if (!emsNativeName.startsWith("?")
				&& !emsNativeName.endsWith("*")) {
			searchMode = MatchMode.EXACT;
		}

		emsNativeName = emsNativeName.replace("?", "").replace("*", "");
		DetachedCriteria criteria = DetachedCriteria.forClass(className);
		criteria = criteria.add(getStatusCriteria());

		criteria.setProjection(Projections.distinct(Projections
				.property("emsNativeName")));

		return getHibernateTemplate().findObjsByCriteria(criteria, true, false);

	}

	/**
	 * Invalidate all.
	 * 
	 * @param objList
	 *            the obj list
	 * @throws DAOException
	 *             the dAO exception
	 */
	private void invalidateAll(Session session) throws DAOException {

		/*
		// NetworkEntity to className;
		org.hibernate.Query query = session
				.createQuery("from "+ className + " as ne  where ne.status != :status and ne.invalidateDate is null");
		query.setParameter("status", AppConstants.NE_STATUS_INACTIVE);
		ScrollableResults scrollableResults = query.setFetchSize(1000).scroll(
				ScrollMode.FORWARD_ONLY);
		int count = 0;
		while (scrollableResults.next()) {
			System.out.println("count is:" + count);
			Object object = scrollableResults.get(0);

			if (object instanceof NetworkEntity) {
				((NetworkEntity) object).invalidate();
			}

			if (++count % 50 == 0) {
				session.flush();
				session.clear();
			}

		}

		session.flush();
		session.clear();
		*/
		
		SQLQuery query= session.createSQLQuery("update ce_network_entity set " +
				"status= 'inactive', invalidatedate = sysdate " +
				"where status='active'");

		query.executeUpdate();
	}
	
	
	
	private void invalidateAll(Session session, Class className) throws DAOException {

		// NetworkEntity to className;
		org.hibernate.Query query = session
				.createQuery("from "+ className.getSimpleName() + " as ne " +
						"where ne.status != :status and ne.invalidateDate is null");
		query.setParameter("status", AppConstants.NE_STATUS_INACTIVE);
		ScrollableResults scrollableResults = query.setFetchSize(1000).scroll(
				ScrollMode.FORWARD_ONLY);
		int count = 0;
		while (scrollableResults.next()) {
			//System.out.println("count is: " + count);
			CommonLogger.info(this, "count is: " + count);
			Object object = scrollableResults.get(0);

			if (object instanceof NetworkEntity) {
				((NetworkEntity) object).invalidate();
			}

			if (++count % 50 == 0) {
				session.flush();
				session.clear();
			}
		}

		session.flush();
		session.clear();
	}

	/**
	 * Gets the status criteria.
	 * 
	 * @return the status criteria
	 */
	public Criterion getStatusCriteria() {

		return Restrictions.and(
				Restrictions.eq("status", AppConstants.NE_STATUS_ACTIVE),
				Restrictions.isNull("invalidateDate"));

	}

	/**
	 * Gets the hibernate template.
	 * 
	 * @return the hibernate template
	 */
	public HibernateTemplate getHibernateTemplate() {
		return hibernateTemplate;
	}

	/**
	 * Sets the hibernate template.
	 * 
	 * @param hibernateTemplate
	 *            the new hibernate template
	 */
	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}

	/**
	 * Find.
	 * 
	 * @param clazz
	 *            the clazz
	 * @param id
	 *            the id
	 * @return the object
	 * @throws DAOException
	 *             the dAO exception
	 */
	protected Object find(Class clazz, long id) throws DAOException {
		Object obj = null;

		Session session = HibernateUtil.openSession();
		try {

			session.beginTransaction();
			obj = session.get(clazz, id);
			session.getTransaction().commit();
		} catch (Exception ex) {
			if (session.getTransaction().isActive()) {
				session.getTransaction().rollback();
			}
			throw new DAOException(ex);
		} finally {
			HibernateUtil.close(session);

		}

		return obj;
	}

	/**
	 * Gets the wild card criterion.
	 * 
	 * @param propertyName
	 *            the property name
	 * @param name
	 *            the name
	 * @return the wild card criterion
	 * @throws DAOException
	 *             the dAO exception
	 */
	public Criterion getWildCardCriterion(String propertyName, String name)
			throws DAOException {

		name = name.replaceAll("\\?", "%");

		name = name.replaceAll("\\*", "%");

		return Restrictions.like(propertyName, name);
	}

	public Criterion getDateCompareCriterion(String propertyName,
			Date startDate, Date endDate) throws DAOException {

	    // modified by Jun on 20120321
	    /*
		if (endDate == null) {
			endDate = DateUtil.NO_EXPIRE;
		}
		return Restrictions.between(propertyName, startDate, endDate);
		*/
	    Criterion ctS = null;
	    Criterion ctE = null;
	    
	    if(null != startDate) {
	        ctS = Restrictions.ge(propertyName, startDate);
	    }    
	    
	    if(null != endDate) {
            ctE = Restrictions.le(propertyName, endDate);
	    }
	    
	    if(null != ctS && null != ctE) {
	        return Restrictions.and(ctS, ctE);
	    }
	    else if(null != ctS) {
	        return ctS;
	    }
	    else if(null != ctE) {
	        return ctE;
	    }
	    
	    return null;
	}
	
	// created by Jun on 20120321
	public void getDateCompareCriterion(DetachedCriteria criteria, String propertyName,
            Date startDate, Date endDate) throws DAOException {
        
        if(null != startDate) {
            criteria.add(Restrictions.ge(propertyName, startDate));
        }    
        
        if(null != endDate) {
            criteria.add(Restrictions.le(propertyName, endDate));
        }
    }

}
